package com.asen.commons.core.base.controller;

import com.asen.commons.core.base.domain.Core;
import com.asen.commons.core.base.dto.CoreDto;
import com.asen.commons.constants.BaseConstant;
import com.asen.commons.annotation.Lock;
import com.asen.commons.core.base.service.CoreService;
import com.asen.commons.core.meta.listener.PropertyProcessListener;
import com.asen.commons.core.utils.EntityUtils;
import com.asen.commons.utils.BaseAssert;
import com.asen.commons.utils.CollectionUtils;
import com.asen.commons.core.base.result.ApiResult;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 业务基础Controller
 *
 * @author Gary
 * @version 1.0
 * @date 2018-11-30
 */
public abstract class AbstractCoreController<T extends Core, D, V, S extends CoreService<T>> extends AbstractListController<T, D, V, S> {

    @Lock
    @ApiOperation(value = "新增", httpMethod = BaseConstant.API_POST_METHOD)
    @PostMapping(value = {"/add"})
    public ApiResult<Long> add(@Validated @RequestBody D dto) throws Exception {
        T model = null;

        addValidate(dto);

        if (getDoClass().equals(getDtoClass())) {
            model = (T) dto;
        } else {
            model = newModel();
        }

        buildAdd(model, dto);
        doAdd(model);

        return success(model.getId(), "新增成功");
    }

    @Lock
    @ApiOperation(value = "修改", httpMethod = BaseConstant.API_POST_METHOD)
    @PostMapping(value = "/mod")
    public ApiResult<Long> mod(@Validated @RequestBody D dto) throws Exception {
        T model = null;
        modValidate(dto);
        if (getDoClass().equals(getDtoClass())) {
            model = (T) dto;
        } else {
            model = newModel();
        }
        buildMod(model, dto);
        doMod(model);
        return success(model.getId(), "更新成功");
    }

    @Lock
    @ApiOperation(value = "删除", httpMethod = BaseConstant.API_POST_METHOD)
    @PostMapping(value = "/del")
    public ApiResult<String> del(@RequestBody CoreDto dto) throws Exception {
        Set<Long> ids = new HashSet<>();

        if (dto.getId() != null) {
            ids.add(dto.getId());
        }

        if (dto.getIds() != null) {
            ids.addAll(dto.getIds());
        }

        BaseAssert.check(CollectionUtils.isNotEmpty(ids), "参数id或ids不能为空");

        for (Long id : ids) {
            if (id == null || id == 0L) {
                continue;
            }

            doDel(id);
        }
        return success("删除成功");
    }

    @Lock(value = Lock.ALL)
    @ApiOperation(value = "批量删除", httpMethod = BaseConstant.API_POST_METHOD)
    @PostMapping(value = "/batchDel")
    public ApiResult<String> batchDel(@RequestBody List<Long> ids) throws Exception {
        BaseAssert.notNull(ids, "参数ids不能为空");
        List<T> list = new ArrayList<>();
        for (Long id : ids) {
            if (id == null || id == 0L) {
                continue;
            }

            T model = newModel();
            model.setId(id);
            list.add(model);
        }
        getService().batchRemove(list);
        return success("删除成功");
    }

    protected void addValidate(final D dto) throws Exception {
        validate(dto);
    }

    protected void modValidate(final D dto) throws Exception {
        validate(dto);
    }

    protected void validate(final D dto) throws Exception {
        BaseAssert.notNull(dto, "请求参数不能为空");
    }

    protected void doAdd(T model) throws Exception {
        getService().add(model);
    }

    protected void doMod(T model) throws Exception {
        getService().update(model);
    }

    protected void doDel(Long id) throws Exception {
        T model = newModel();
        model.setId(id);
        getService().remove(model);
    }

    protected void buildAdd(final T model, final D dto) throws Exception {
        buildModel(model, dto);
    }

    protected void buildMod(final T model, final D dto) throws Exception {
        buildModel(model, dto);
    }

    protected void buildModel(final T model, final D dto) throws Exception {
        if (getDoClass().equals(getDtoClass())) {
            return;
        }

        EntityUtils.copyProperties(dto, model, new PropertyProcessListener() {
            @Override
            public boolean processed(String propName) throws Exception {
                return buildField(model, dto, propName);
            }
        });
    }

    /**
     * 返回true，覆盖默认逻辑
     *
     * @param model
     * @param dto
     * @param fieldName dto的属性名
     * @return
     * @throws Exception
     */
    protected boolean buildField(T model, D dto, String fieldName) throws Exception {
        return false;
    }

    protected T newModel() throws Exception {
        return (T) getDoClass().newInstance();
    }
}
